package model

import (
	"fmt"
	"gitee.com/liumou_site/gcs"
	"gitee.com/liumou_site/gf"
	"gitee.com/liumou_site/logger"
	"os"
	"path/filepath"
)

// DefaultBackupStart 执行默认的备份启动流程。
// 该函数首先调用 DefaultBackupSSH 方法进行 SSH 配置的默认备份，
// 如果 DefaultBackupSSH 返回错误，则立即返回该错误。
// 如果 DefaultBackupSSH 成功执行，则调用 bakSSH 函数对目标进行备份。
// 返回值：
//   - error: 如果过程中出现错误，则返回相应的错误信息；否则返回 nil。
func (i Info) DefaultBackupStart() error {
	if CheckSSHListening(i) != nil {
		GetLanguageManager().Error("服务异常,无法进行备份", "Service exception, unable to backup")
		os.Exit(1)
	}
	// 执行默认的 SSH 备份配置
	err := i.DefaultBackupSSH()
	if err != nil {
		return err
	}

	// 对目标进行备份
	bakSSH(i.Target, i.Init)
	return nil
}

// DefaultBackupSSH 用于备份 /etc/ssh 目录到指定目标路径。
// 该函数会检查源路径是否为软链接，如果是软链接，则获取其实际路径后再进行备份。
// 备份过程中会根据调试模式和语言设置输出相应的日志信息。
//
// 返回值:
//   - error: 如果备份过程中出现错误，则返回相应的错误信息；否则返回 nil。
func (i Info) DefaultBackupSSH() error {
	// 将整个 /etc/ssh 目录进行备份
	if i.Debug {
		GetLanguageManager().Debug("开始备份", "Start backing up")
	}
	f := gf.NewFile(i.Target)
	f.IsDir()
	f.Exists()
	if f.IsDirs {
		if !i.Init {
			GetLanguageManager().Info("目标路径已存在，跳过备份: ", "The target path already exists, skip backup: ", i.Target)
			return nil
		}
	}
	i.Source = "/etc/ssh"
	symlink, err := IsSymlink(i.Source)
	if err != nil {
		logger.Error("Error checking if the configuration file is a symlink:", err)
		os.Exit(3)
	}
	if symlink {
		// 获取软链接源路径
		i.Source, err = os.Readlink("/etc/ssh")
		if err != nil {
			logger.Error("Error reading the symlink:", err)
			os.Exit(2)
		}
	}
	run := gcs.NewShell()
	cmd := fmt.Sprintf("cp -rf %s %s", i.Source, i.Target)
	run.RunShell(cmd)
	if run.Err != nil {
		GetLanguageManager().Error("备份失败: ", "Backup failed: ", run.Err.Error())
		fmt.Println(cmd)
		return run.Err
	} else {
		GetLanguageManager().Info("备份成功", "Backup successful")
		return nil
	}
}

// bakSSH 函数用于备份系统中的 sshd 可执行文件到指定目录。
// 该函数首先检查 /usr/sbin/sshd 是否为软链接，如果是，则获取其实际指向的路径。
// 然后，函数会创建目标目录，并将 sshd 文件复制到该目录中。
// 如果备份过程中出现任何错误，函数将记录错误日志并退出。
//
// 参数:
//   - dst: 目标目录路径，用于存放备份的 sshd/ssh 文件。
//   - cover: 是否覆盖目标目录中的文件。

func bakSSH(dst string, cover bool) {
	// 默认源文件路径为 /usr/sbin/sshd
	bakBinFile(dst, "/usr/sbin/sshd", cover)
	bakBinFile(dst, "/usr/bin/ssh", cover)
}

// bakBinFile 用于备份指定的二进制文件到目标目录。
// 该函数首先检查源文件是否为软链接，如果是软链接，则获取其实际指向的路径。
// 然后创建目标目录，并将源文件复制到目标目录中。
// 如果在此过程中出现任何错误，函数将记录错误日志并退出程序。
//
// 参数:
//   - dstDir: 目标目录路径，备份文件将被复制到此目录。
//   - src: 源文件路径，需要备份的文件。
//   - cover: 是否覆盖目标目录中的文件。
func bakBinFile(dstDir, src string, cover bool) {
	// 检查目标是否已存在
	file_ := filepath.Join(dstDir, filepath.Base(src))
	f := gf.NewFile(file_)
	f.IsFile()
	f.Exists()
	if f.IsFiles && !cover {
		GetLanguageManager().Info("目标文件已存在，跳过备份: ", "Target file already exists, skip backup: ", file_)
		return
	}
	// 检查源文件是否为软链接
	symlink, err := IsSymlink(src)
	if err != nil {
		GetLanguageManager().Error("检查配置文件是否为软链接时出错: ", "Error checking if the configuration file is a symlink: ", err)
		os.Exit(3)
	}

	// 如果是软链接，获取其实际指向的路径
	if symlink {
		src, err = os.Readlink(src)
		if err != nil {
			GetLanguageManager().Error("读取软链接时出错: ", "Error reading the symlink: ", err)
			os.Exit(2)
		}
	}
	f = gf.NewFile(dstDir)
	f.IsDir()
	f.Exists()
	if !f.IsDirs {
		// 创建目标目录，权限设置为 0755
		err = os.MkdirAll(dstDir, 0755)
		if err != nil {
			GetLanguageManager().Error("创建目标目录时出错: ", "Error creating destination directory: ", err)
			os.Exit(4)
		}
	}

	cmd := fmt.Sprintf("cp -rf %s %s", src, dstDir)
	run := gcs.NewShell()
	run.RunShell(cmd)
	if run.Err != nil {
		GetLanguageManager().Error("复制文件时出错: ", "Error copying file: ", run.Err)
		os.Exit(5)
	}
	// 记录备份成功日志
	GetLanguageManager().Info("备份成功: [ "+src+" ] -> [ "+dstDir+" ]", "Backup successful: [ "+src+" ] -> [ "+dstDir+" ]")
}
